package infod

import (
	"time"

	"github.com/globalsign/mgo"
	"github.com/globalsign/mgo/bson"
	"github.com/pkg/errors"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	cinfod "gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/infod"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/repo/mgorepo/baser"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

var (
	_ cinfod.InfoRepo = &infoRepo{}
)

type infoRepo struct {
	baser.BaseRepo
}

// 新增信息
func (r *infoRepo) AddInfo(ctx ddd.Context, info cinfod.InfoDesc) (id string, err error) {
	ci := &collInfo{}
	ci.FullDesc(info)
	ci.Creator = ctx.UID()
	ci.InfoID = r.NextID()
	ci.CreTime = time.Now()
	ci.Updater = ci.Creator
	ci.UpdateTime = ci.CreTime
	err = r.DBInsert(ctx, ci)
	if err != nil {
		return "", err
	}
	_ = r.appendAction(ctx, ci.InfoID, "新增信息")
	return ci.InfoID, nil
}

// 获取指定信息：根据唯一标识获取信息实体
func (r *infoRepo) GetInfo(ctx ddd.Context, infoid string) (ia *cinfod.InfoAggregate, err error) {
	a, err := r.GetByCollAggregate(ctx, &collInfo{InfoID: infoid})
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	ia = a.(*cinfod.InfoAggregate)
	return
}
func (r *infoRepo) parseSearch(is cinfod.InfoSearch) bson.M {
	query := bson.M{}

	if is.Key != "" {

		query["$or"] = []bson.M{
			bson.M{"title": bson.M{"$regex": is.Key}},
			bson.M{"content": bson.M{"$regex": is.Key}},
		}
	}
	if is.UID == "" && is.OrgID == "" {
		if is.Range == 1 {
			query["org"] = ""
			query["owner"] = ""
		}
	} else {
		if is.UID != "" {
			query["owner"] = is.UID
		}
		if is.OrgID != "" {
			query["org"] = is.OrgID
		}
	}
	if is.ColumnID != "" {
		query["columnId"] = is.ColumnID
	}
	if len(is.Status) > 0 {

		query["status"] = bson.M{"$in": is.Status}
	}
	if len(is.Tags) > 0 {

		query["tags"] = bson.M{"$all": is.Tags}
	}
	if len(is.Extral) > 0 {
		for k, v := range is.Extral {
			switch vv := v.(type) {
			case string:
				query["extras."+k] = vv
			case float64:
				query["extras."+k] = vv
			case map[string]interface{}:
				b := bson.M{}
				if gt, ok := vv[">"]; ok {
					b["$gt"] = gt
				}
				if gt, ok := vv[">="]; ok {
					b["$gte"] = gt
				}
				if gt, ok := vv["<"]; ok {
					b["$lt"] = gt
				}
				if gt, ok := vv["<="]; ok {
					b["$lte"] = gt
				}
				if len(b) > 0 {
					query["extras."+k] = b
				}
			default:
			}
		}
	}
	if is.Creator != "" {
		query["creator"] = is.Creator
	}
	if is.Publisher != "" {
		query["publisher"] = is.Publisher
	}
	if is.PubTime != nil {
		if ptime := r.JSONSchTime2Bson(*is.PubTime); ptime != nil {
			query["publishTime"] = ptime
		}
	}
	if is.CreTime != nil {
		if ptime := r.JSONSchTime2Bson(*is.CreTime); ptime != nil {
			query["creTime"] = ptime
		}
	}

	return query
}

// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
// total 总数量
func (r *infoRepo) QueryPage(ctx ddd.Context, is cinfod.InfoSearch, pi common.PageInfo) (npi common.PageResult, result []cinfod.InfoAggregate, err error) {
	query := r.parseSearch(is)

	var cs []collInfo

	npi, err = r.DBQueryPage(ctx, collNameInfo, pi, "_id", query, nil, nil, &cs)

	if err != nil {
		if err == mgo.ErrNotFound {
			err = nil
			npi.End = 1
			return
		}
		err = errors.Wrapf(err, "查询信息失败。查询条件:%v 。分页信息:%v", is, pi)
		return
	}
	if len(cs) == 0 {
		npi.End = 1
		return
	}
	result = make([]cinfod.InfoAggregate, 0, len(cs))
	for _, c := range cs {
		ia := c.ToInfoAggregate()
		// 初始化聚合
		ia.Init(ia, r.AggregateRoot(), c.InfoID)
		result = append(result, *ia)
	}

	return
}

// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
// total 总数量
func (r *infoRepo) QueryNum(ctx ddd.Context, is cinfod.InfoSearch) (num int, err error) {
	query := r.parseSearch(is)
	num, err = r.DBQueryNum(ctx, collNameInfo, query)
	if err != nil {
		if err == mgo.ErrNotFound {
			err = nil
			return
		}
		err = errors.Wrapf(err, "查询匹配信息数量失败。查询条件:%v ", is)
		return
	}
	return
}

// 修改信息
func (r *infoRepo) UpdateDesc(ctx ddd.Context, infoid string, info cinfod.InfoDesc) error {
	update := bson.M{
		"columnId":   info.ColumnID,
		"title":      info.Title,
		"subTitle":   info.SubTitle,
		"listMode":   info.ListMode,
		"extras":     info.Extras,
		"icon":       info.Icon,
		"from":       info.From,
		"banner":     info.Banner,
		"desc":       info.Desc,
		"tags":       info.Tags,
		"updater":    ctx.UID(),
		"updateTime": time.Now(),
		"context":    info.Content,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionUpdateDesc)
}

// 修改信息
func (r *infoRepo) UpdateDescToInit(ctx ddd.Context, infoid string, info cinfod.InfoDesc) error {
	update := bson.M{
		"columnId":   info.ColumnID,
		"title":      info.Title,
		"subTitle":   info.SubTitle,
		"listMode":   info.ListMode,
		"extras":     info.Extras,
		"icon":       info.Icon,
		"from":       info.From,
		"banner":     info.Banner,
		"desc":       info.Desc,
		"tags":       info.Tags,
		"updater":    ctx.UID(),
		"updateTime": time.Now(),
		"context":    info.Content,
		"status":     cinfod.IStatusInit,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionUpdateDescToInit)
}

// 修改信息
func (r *infoRepo) UpdateExtral(ctx ddd.Context, infoid string, info map[string]interface{}) error {
	update := bson.M{}
	for k, v := range info {
		update["extras."+k] = v
	}
	return r.updateCollAggregate(ctx, infoid, update, actionUpdateExtral)
}

// 删除信息 标记删除
func (r *infoRepo) DeleteInfo(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status":     cinfod.IStatusDeleted,
		"deleter":    ctx.UID(),
		"deleteTime": time.Now(),
	}
	err := r.DBUpdateID(ctx, collNameInfo, infoid, update)
	if err != nil {
		return err
	}
	err = r.DeleteCache(ctx, &collInfo{InfoID: infoid})
	if err != nil {
		log.Warnf("删除信息%v缓存时失败：%v", infoid, err)
	}
	_ = r.appendAction(ctx, infoid, actionDelete)
	return nil
}

// 恢复删除信息
func (r *infoRepo) RecoverInfo(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status":     cinfod.IStatusInit,
		"deleter":    ctx.UID(),
		"deleteTime": time.Now(),
	}
	return r.updateCollAggregate(ctx, infoid, update, actionRecover)
}

// 彻底删除指定信息
func (r *infoRepo) DestroyInfoByID(ctx ddd.Context, infoid string) error {
	return r.DestroyByCollAggregate(ctx, &collInfo{InfoID: infoid})
}

// 根据一组信息id获取信息列表
// 列表按信息编号的顺序返回
func (r *infoRepo) FullInfos(ctx ddd.Context, infoids []string) (result []cinfod.InfoAggregate, err error) {
	query := bson.M{
		"_id": bson.M{"$in": infoids},
	}
	var cs []collInfo

	err = r.DBQuery(ctx, collNameInfo, query, nil, nil, &cs)

	ms := make(map[string]collInfo)
	for _, v := range cs {
		ms[v.InfoID] = v
	}
	for _, v := range infoids {
		if c, ok := ms[v]; ok {
			a := c.ToInfoAggregate()
			a.Init(a, r.AggregateRoot(), a.InfoID)
			result = append(result, *a)
		}
	}

	return
}

// 提交审核
func (r *infoRepo) CommitCheck(ctx ddd.Context, infoid string) error {
	// TODO: 还没有实现操作记录
	update := bson.M{
		"status": cinfod.IStatusCheckWait,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionSubmit)
}

// 审核通过
func (r *infoRepo) CheckOK(ctx ddd.Context, infoid, content string) error {
	// TODO: 还没有实现审核意见记录和审核记录
	update := bson.M{
		"status":       cinfod.IStatusCheckOk,
		"checker":      ctx.UID(),
		"checkTime":    time.Now(),
		"checkContent": content,
		"checkResult":  1,
	}

	return r.updateCollAggregate(ctx, infoid, update, actionCheckOK)
}

// 审核不通过
func (r *infoRepo) CheckNo(ctx ddd.Context, infoid, content string) error {
	// TODO: 还没有实现审核意见记录和审核记录
	update := bson.M{
		"status":       cinfod.IStatusCheckNO,
		"checker":      ctx.UID(),
		"checkTime":    time.Now(),
		"checkContent": content,
		"checkResult":  0,
	}

	return r.updateCollAggregate(ctx, infoid, update, actionCheckNo)
}

// 发布
func (r *infoRepo) Publish(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status":      cinfod.IStatusPublished,
		"publisher":   ctx.UID(),
		"publishTime": time.Now(),
	}

	return r.updateCollAggregate(ctx, infoid, update, actionPublish)

}

// 取消发布
func (r *infoRepo) Unpublish(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status": cinfod.IStatusNoPublish,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionUnpublish)
}

// 禁止发布
func (r *infoRepo) ProhibitPublish(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status": cinfod.IStatusProhibitPublish,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionProhibitPublish)
}

// 取消禁止发布
func (r *infoRepo) CancelProhibitPublish(ctx ddd.Context, infoid string) error {
	update := bson.M{
		"status": cinfod.IStatusNoPublish,
	}
	return r.updateCollAggregate(ctx, infoid, update, actionCancelProhibitPublish)
}

// 取消禁止发布
func (r *infoRepo) updateCollAggregate(ctx ddd.Context, infoid string, update interface{}, desc string) error {
	if err := r.DBUpdateCollAggregate(ctx, &collInfo{InfoID: infoid}, update); err != nil {
		return err
	}
	_ = r.appendAction(ctx, infoid, desc)
	return nil
}
func (r *infoRepo) appendAction(ctx ddd.Context, infoid, action string) error {
	cinfo := &collInfoOpLog{
		ID:       r.NextID(),
		InfoID:   infoid,
		Operator: ctx.UID(),
		OpTime:   time.Now(),
		Action:   action,
	}
	return r.DBInsert(ctx, cinfo)

}
